#ifndef __GLF_MATH_VEC2_H_INCLUDED__
#define __GLF_MATH_VEC2_H_INCLUDED__

#include <glf/math/functions.h>

namespace glf { 

template<typename T> struct vec2;
template<typename T> struct Vec2;

typedef vec2<float> vec2f;
typedef Vec2<float> Vec2f;

typedef vec2<int> vec2i;
typedef Vec2<int> Vec2i;

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

template<typename T>
struct vec2
{
	T x,y;
};

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

template<typename T>
struct Vec2 : public vec2<T>
{
    Vec2() ;
    Vec2(const T* p) ;
    Vec2(T fx, T fy) ;
    Vec2(const vec2<T>& v) ;

    operator T*() ;
    operator const T*() const ;

    Vec2<T>& operator+=(const Vec2<T>& rhs) ;
    Vec2<T>& operator-=(const Vec2<T>& rhs) ;
    Vec2<T>& operator*=(T f) ;
    Vec2<T>& operator/=(T f) ;

    Vec2<T> operator+() const ;
    Vec2 operator-() const ;

    Vec2 operator+(const Vec2<T>& rhs) const ;
    Vec2 operator-(const Vec2<T>& rhs) const ;
    Vec2 operator*(T f) const ;
    Vec2 operator/(T f) const ;
    bool operator==(const Vec2<T>& rhs) const ;
    bool operator!=(const Vec2<T>& rhs) const ;
	bool operator<(const Vec2<T>& rhs) const ;
	bool operator<=(const Vec2<T>& rhs) const ;
	bool operator>(const Vec2<T>& rhs) const ;
	bool operator>=(const Vec2<T>& rhs) const ;

    T LenSq() const ;
	T Len() const;
	T DistSq(const Vec2<T>& v2) const; 
	T Dist(const Vec2<T>& v2) const;

	//! Min of all components
	void Min(const Vec2<T>& v2);
	
	//! Max of all components
	void Max(const Vec2<T>& v2);

};

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

template<typename T>
Vec2<T>::Vec2() 
{
	 
}

template<typename T>
Vec2<T>::Vec2(const T* p) 
{
	 this->x = p[0]; 
	 this->y = p[1]; 
}

template<typename T>
Vec2<T>::Vec2(T fx, T fy) 
{
	 this->x = fx; 
	 this->y = fy; 
}

template<typename T>
Vec2<T>::Vec2(const vec2<T>& v) 
{
	 this->x = v.x; 
	 this->y = v.y; 
}


template<typename T>
Vec2<T>::operator T*() 
{
	 return &this->x; 
}

template<typename T>
Vec2<T>::operator const T*() const 
{
	 return &this->x; 
}


template<typename T>
Vec2<T>& Vec2<T>::operator+=(const Vec2<T>& rhs) 
{
	 this->x += rhs.x; 
	 this->y += rhs.y; 
	 return *this; 
}

template<typename T>
Vec2<T>& Vec2<T>::operator-=(const Vec2<T>& rhs) 
{
	 this->x -= rhs.x; 
	 this->y -= rhs.y; 
	 return *this; 
}

template<typename T>
Vec2<T>& Vec2<T>::operator*=(T f) 
{
	 this->x *= f;
	 this->y *= f;
	 return *this; 
}

template<typename T>
Vec2<T>& Vec2<T>::operator/=(T f) 
{
	 T r = 1 / f;
	 this->x *= r;
	 this->y *= r;
	 return *this; 
}


template<typename T>
Vec2<T> Vec2<T>::operator+() const 
{
	 return *this; 
}

template<typename T>
Vec2<T> Vec2<T>::operator-() const 
{
	 return Vec2(-this->x, -this->y); 
}


template<typename T>
Vec2<T> Vec2<T>::operator+(const Vec2<T>& rhs) const 
{
	 return Vec2(this->x + rhs.x, this->y + rhs.y); 
}

template<typename T>
Vec2<T> Vec2<T>::operator-(const Vec2<T>& rhs) const 
{
	 return Vec2(this->x - rhs.x, this->y - rhs.y); 
}

template<typename T>
Vec2<T> Vec2<T>::operator*(T f) const 
{
	return Vec2(this->x * f, this->y * f);
}

template<typename T>
Vec2<T> Vec2<T>::operator/(T f) const 
{
	 T r = T(1) / f;
	 return Vec2(this->x * r, this->y * r); 
}

template<typename T>
bool Vec2<T>::operator==(const Vec2<T>& rhs) const 
{
	 return this->x == rhs.x && this->y == rhs.y; 
}

template<typename T>
bool Vec2<T>::operator!=(const Vec2<T>& rhs) const 
{
	 return this->x != rhs.x || this->y != rhs.y; 
}

template<typename T>
bool Vec2<T>::operator<(const Vec2<T>& rhs) const 
{
	 return this->x < rhs.x && this->y < rhs.y; 
}

template<typename T>
bool Vec2<T>::operator<=(const Vec2<T>& rhs) const 
{
	 return this->x <= rhs.x && this->y <= rhs.y; 
}

template<typename T>
bool Vec2<T>::operator>(const Vec2<T>& rhs) const 
{
	 return this->x > rhs.x && this->y > rhs.y; 
}

template<typename T>
bool Vec2<T>::operator>=(const Vec2<T>& rhs) const 
{
	 return this->x >= rhs.x && this->y >= rhs.y; 
}

template<typename T>
T Vec2<T>::LenSq() const 
{
	 return this->x * this->x + this->y * this->y;
}

template<typename T>
T Vec2<T>::Len() const 
{
	return Sqrt(this->x * this->x + this->y * this->y); 
}


template<typename T>
T Vec2<T>::Dist(const Vec2<T>& v2) const 
{
	return Sqrt((this->x - v2.x)*(this->x - v2.x) + (this->y - v2.y)*(this->y - v2.y));
}


template<typename T>
T Vec2<T>::DistSq(const Vec2<T>& v2) const 
{
	 return (this->x - v2.x)*(this->x - v2.x) + (this->y - v2.y)*(this->y - v2.y);
}

template<typename T>
void Vec2<T>::Min(const Vec2<T>& v2)
{
	this->x = glf::Min(this->x, v2.x);
	this->y = glf::Min(this->y, v2.y);
}

template<typename T>
void Vec2<T>::Max(const Vec2<T>& v2)
{
	this->x = glf::Max(this->x, v2.x);
	this->y = glf::Max(this->y, v2.y);
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

} //namespace glf

#endif
